package com.li.springbootproject.service.transaction;

import com.li.springbootproject.domain.User;
import com.li.springbootproject.mapper.UserMapper;
import com.li.springbootproject.utils.SpringContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;

/**
 * @author LiDong
 * @version 1.0.0
 * @className TransactionServiceImpl.java
 * @createTime 2021年06月07日 20:15:00
 */
@Service
public class TransactionServiceImpl implements TransactionService {


    /**
     * 事务失效的几种情况。
     * 1.数据库引擎不支持事务
     * 2.没有被spring管理
     * 3.方法不是public的
     * 4.自调用问题
     * 5.数据源没有配置事务管理器
     * 6.事务的扩展上不支持事务
     * 7.异常被吃
     * 8.异常类型错误
     */

    private static final Logger logger = LoggerFactory.getLogger(TransactionServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DataSourceTransactionManager transactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

    /**
     * 内嵌型事务只有 里面和外面都执行成功后才会成功
     */
    @Override
    @Transactional
    public void ransactionOne() {
        User user = new User();
        user.setUsername("张三");
        userMapper.insertUser(user);
        methodOne();
        int a = 3 / 0;
        logger.info(String.valueOf(a));
    }

    /**
     * 使用此种方式会使事务失效
     */
    @Override
    public void transactionTwo() {
        new Thread(this::methodTwo).start();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void transactionThree() {
        User user = new User();
        user.setUsername("李四");
        userMapper.insertUser(user);
        int a = 5 / 0;
        logger.info(String.valueOf(a));
    }


    /**
     * 不同的事务提交报错
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void transactionFour() {
        User user = new User();
        user.setUsername("张三");
        user.setId(1);
        userMapper.updateUser(user);

        DataSource dataSource = SpringContextUtils.getBean(DataSource.class);
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            connection.prepareStatement("update user set username ='王五', gender='2' where id ='1'").executeUpdate();
        } catch (SQLException throwables) {
            logger.error("Error Occur:{}", throwables.getMessage(), throwables);
        }
    }

    /**
     * 手动提交事务
     * 读已经提交的数据
     */
    @Override
    public void transactionFive() {
        TransactionStatus transaction = transactionManager.getTransaction(transactionDefinition);
        User user = new User();
        user.setUsername("张三");
        user.setId(1);
        userMapper.updateUser(user);
        // 手动提交
        transactionManager.commit(transaction);
        updateUserOne(user);
    }

    public void updateUserOne(User user) {
        DataSource dataSource = SpringContextUtils.getBean(DataSource.class);
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            connection.setAutoCommit(true);
            // 设置为读已经提交了的
            connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            connection.prepareStatement("update user set username ='王五', gender='2' where id ='1'").executeUpdate();
        } catch (SQLException throwables) {
            logger.error("Error Occur:{}", throwables.getMessage(), throwables);
        } finally {
            if (Objects.nonNull(connection)) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    logger.error("Error Occur:{}", throwables.getMessage(), throwables);
                }
            }
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    public void methodTwo() {
        User user = new User();
        user.setUsername("李四");
        userMapper.insertUser(user);
        int a = 5 / 0;
        logger.info(String.valueOf(a));
    }

    @Transactional(propagation = Propagation.NESTED)
    public void methodOne() {
        User user = new User();
        user.setUsername("李四");
        userMapper.insertUser(user);
    }


}
